# 渐变

from PyQt5.QtWidgets import QWidget, QMenu, QAction, QColorDialog
from PyQt5.QtCore import Qt, QPointF, QRect, QSize, QPoint
from PyQt5.QtGui import QGradient, QLinearGradient, QPainter, QPen, QColor

from GUI.Widget.ControllerTag import ControllerTag


class GradientDisplay(QWidget):
    gradient = None  # 渐变组件

    def __init__(self, parent=None, gradient=None):
        super().__init__(parent)
        self.gradient = gradient

    def paintEvent(self, event):
        if self.gradient:
            pq = QPainter()
            pq.begin(self)
            # 反走样
            pq.setRenderHint(QPainter.Antialiasing, True)
            # 设置画笔颜色、宽度
            pq.setPen(QPen(QColor(0, 0, 0), 0))
            # 设置画刷填充
            pq.setBrush(self.gradient)
            pq.drawRect(self.gradientRect)
            pq.end()

    def getColor(self, rate):
        """
        获取渐变器某位置的颜色
        :param rate: 0 到 1
        :return:
        """
        color = QColor(0, 0, 0)
        if not self.gradient:
            return color
        stops = self.gradient.stops()
        if rate >= 1:
            color = stops[-1][1]
        else:
            # 找左右端点
            for i in range(0, len(stops) - 1):
                if stops[i][0] <= rate < stops[i + 1][0]:
                    k = (rate - stops[i][0]) / (stops[i + 1][0] - stops[i][0])
                    color1 = stops[i][1]
                    color2 = stops[i + 1][1]
                    color.setRed(round(color1.red() + (color2.red() - color1.red()) * k))
                    color.setGreen(round(color1.green() + (color2.green() - color1.green()) * k))
                    color.setBlue(round(color1.blue() + (color2.blue() - color1.blue()) * k))
                    color.setAlpha(round(color1.alpha() + (color2.alpha() - color1.alpha()) * k))
        return color


class Tag(ControllerTag):
    color = QColor(255, 255, 255)    # tag 渐变原色

    def __init__(self, parent, controller=None):
        super().__init__(parent, controller)
        self.initUI()

    def initUI(self):
        self.show()

    @property
    def toStop(self):
        return (self.xRate, self.color)

    @property
    def x2(self):
        """
        上顶点坐标
        :return:
        """
        return self.x() + self.width() / 2

    @property
    def y2(self):
        """
        上顶点坐标
        :return:
        """
        return self.y()

    def move2(self, x, y):
        """
        移动部件 上顶点（x,y)
        :param x: int
        :param y: int
        :return:
        """
        self.xRate = x / self.Parent.width()
        self.yRate = y / self.Parent.height()
        x = x - self.width() / 2
        self.move(x, y)

    def updatePos(self):
        x = self.Parent.width() * self.xRate
        y = self.Parent.height() * self.yRate
        x = x - self.width() / 2
        self.move(x, y)

    def setXRate(self, x):
        self.move2(x * self.Parent.width(), self.y2)

    def paintEvent(self, event):
        # 绘制三角形
        qp = QPainter()
        qp.begin(self)
        qp.setPen(QPen(QColor(0, 0, 0), 0))
        qp.setBrush(Qt.blue)
        qp.drawPolygon(QPoint(self.width()/2, 0), QPoint(0, self.height()), QPoint(self.width(), self.height()))
        qp.end()

    def mouseDoubleClickEvent(self, event):
        if event.button() == Qt.LeftButton:
            colorWindow = QColorDialog(self.color)
            color = colorWindow.getColor()
            if color.isValid():
                self.color = color
                self.parent().updateGradientStopColor(self)


class GradientController(GradientDisplay):
    gradientRect = None # 渐变区域
    tagList = None  # tag列表
    tagSize = None  # tag大小
    Active = False
    # 组件
    OperatingTag = None
    context = None
    contextPos = None
    contextTag = None

    def __init__(self, parent):
        super().__init__(parent)
        self.tagList = []
        self.__initUI()

    def __initUI(self):
        # 渐变
        gradient = QLinearGradient()
        gradient.setSpread(QGradient.PadSpread)
        self.gradient = gradient
        self.__updateArg()
        #   创建初始tag
        self.initTag()
        # 创建context
        self.initContext()

    def __updateArg(self):
        """
        更新参数
        :return:
        """
        w, h = self.width(), self.height()
        # 渐变区域
        if h*0.1 < 16:   # tag最小高度为16
            h = self.height() - 16
        else:
            h = int(h * 0.9)
        self.gradientRect = QRect(0, 0, w, h)
        # 渐变起始点
        self.gradient.setStart(QPointF(0, h/2))
        self.gradient.setFinalStop(QPointF(w, h / 2))
        # tag 大小
        self.tagSize = QSize(self.height() - h, self.height() - h)

    def __newTag(self, x=0):
        tag = Tag(self, self)
        tag.resize(self.tagSize)
        tag.move2(0, self.gradientRect.height())
        tag.setXRate(x)
        return tag

    def initTag(self):
        tag = self.__newTag(0)
        tag.color = Qt.black
        self.tagList.append(tag)

        tag = self.__newTag(1)
        tag.color = Qt.white
        self.tagList.append(tag)

        stops = []
        for i in range(0, len(self.tagList)):
            tag = self.tagList[i]
            stops.append(tag.toStop)
        self.gradient.setStops(stops)

    def updateGradientStopPos(self):
        stops = []
        for i in range(0, len(self.tagList)):
            tag = self.tagList[i]
            stops.append(tag.toStop)
        self.gradient.setStops(stops)
        self.updateSlot()

    def updateGradientStopColor(self, tag):
        index = self.tagList.index(tag)
        if index > -1:
            stops = self.gradient.stops()
            stops[index] = tag.toStop
            self.gradient.setStops(stops)
            self.updateSlot()

    def updateSlot(self):
        pass

    def initContext(self):
        # Content
        menu = QMenu(self)
        self.context = menu

        Act = QAction("新建", menu)
        menu.addAction(Act)
        Act.triggered.connect(self.__newTagAction)
        menu.newTagAct = Act

        Act = QAction("删除", menu)
        menu.addAction(Act)
        Act.triggered.connect(self.__delTagAction)
        menu.delTagAct = Act

    def contextMenuEvent(self, event):
        self.context.popup(self.mapToGlobal(event.pos()))
        self.contextPos = event.pos()
        tag = self.childAt(event.x(), event.y())
        self.contextTag = tag
        if tag:
            self.context.newTagAct.setVisible(False)
            self.context.delTagAct.setVisible(True)
        else:
            self.context.delTagAct.setVisible(False)
            self.context.newTagAct.setVisible(True)

    def __newTagAction(self):
        if self.contextPos:
            x = self.contextPos.x()
            # 寻找合适的列表位置
            tags = self.tagList
            length = len(tags)
            index = -1
            for i in range(0, length - 1):
                if tags[i].x2 < x < tags[i + 1].x2:  # 找到合适位置
                    index = i
                    break
            if index > -1:
                # 插入
                tag = self.__newTag(x/ self.gradientRect.width())
                tags.insert(index + 1, tag)
                self.updateGradientStopPos()
                self.update()
            else:
                print('插入失败')

    def __delTagAction(self):
        if self.contextTag:
            self.tagList.remove(self.contextTag)
            self.contextTag.deleteLater()
            self.updateGradientStopPos()
            self.update()

    def paintEvent(self, event):
        pq = QPainter()
        pq.begin(self)
        # 反走样
        pq.setRenderHint(QPainter.Antialiasing, True)
        # 设置画笔颜色、宽度
        pq.setPen(QPen(QColor(0, 0, 0), 0))
        # 设置画刷填充
        pq.setBrush(self.gradient)
        pq.drawRect(self.gradientRect)
        pq.end()

    def resizeEvent(self, event):
        self.__updateArg()
        # 更新tag
        for tag in self.tagList:
            tag.resize(self.tagSize)
            tag.updatePos()
            tag.move2(tag.x2, self.gradientRect.height())

    def mouseMoveEvent(self, event):
        if self.Active:
            if self.OperatingTag:
                x = event.pos().x()
                y = event.pos().y()
                # 相邻锚点检查
                tags = self.tagList
                index = tags.index(self.OperatingTag)
                if 0 < index < len(tags) - 1:
                    if x >= tags[index + 1].x2:
                        x = tags[index + 1].x2 - 1
                    elif x <= tags[index - 1].x2:
                        x = tags[index - 1].x2 + 1
                    self.OperatingTag.move2(x, self.OperatingTag.y2)
                    self.updateGradientStopPos()
                    self.update()





